linux进程的同步和互斥锁

您所在的位置:网站首页 linux 进程间互斥 linux进程的同步和互斥锁

linux进程的同步和互斥锁

#linux进程的同步和互斥锁| 来源: 网络整理| 查看: 265

1.互斥锁作用:

互斥锁mutex是用来保护线程间共享的全局变量安全的一种机制,保证多线程中在某一时刻只允许某一个线程对临界区的访问。

2.初始化方式:

互斥锁对象的数据类型是 pthread_mutex_t ;

互斥锁的初始方式分为静态方式和动态方式:

//动态初始化互斥锁方式 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); //静态初始化互斥锁方式 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

3.常用函数:

//阻塞方式加锁 int pthread_mutex_lock(pthread_mutex_t *mutex); //非阻塞方式加锁,如果该互斥体已经被上锁,该调用不会阻塞等待,而会返回一个错误代码,没被加锁则加锁 int pthread_mutex_trylock(pthread_mutex_t *mutex); //解锁 int pthread_mutex_unlock(pthread_mutex_t *mutex); //阻塞等待线程锁,超过固定的时间还不能获取锁,则返回错误 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout); //销毁互斥锁 int pthread_mutex_destroy(pthread_mutex_t *mutex);

4.互斥锁的属性

互斥量属性对象的数据类型为:pthread_mutexattr_t

#include //初始化一个互斥对象的属性 int pthread_mutexattr_init(pthread_mutexattr_t *attr); //回收属性对象 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);

一般有两个属性值得关心:进程共享属性和类型属性。但是Linux下只支持类型属性。

进程共享属性:用来获取和设置互斥量是否被共享

int pthread_mutexattr_getpshared(const pthread_mutexattr_t * restrict attr, int *restrict pshared); int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);

如果属性设置为PTHREAD_PROCESS_SHARED,那么从多个进程共享的内存区域中分配的互斥量就可以用于这些进程的同步。 如果属性设置为PTHREAD_PROCESS_PRIVATE,那么互斥量只能用于一个进程中的多个线程同步。这个是默认的属性。

类型属性:

int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind);

不支持POSIX标准的kind值以NP结尾:不能在可移植的程序中使用

PTHREAD_MUTEX_FAST_NP //默认属性,当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。PTHREAD_MUTEX_RECURSIVE_NP //嵌套锁,允许同一个线程对同一个锁成功获得多次(没有解锁后重新加锁不会死锁),并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。PTHREAD_MUTEX_ERRORCHECK_NP //检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_FAST_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

一个线程调用pthread_mutex_lock获取已经被占用的互斥量的时候,当类型属性为”fast”,该线程会被暂停。当类型属性为”error”,该线程立刻返回一个错误码EDEADLK。当属性为”recursive”,该线程会成功返回(但是mutex对象内部会有一个值记录目前有多少线程占有该互斥量,当所有占有的线程都调用pthread_mutex_unlock,该互斥量才处于未被占有的状态)

支持POSIX标准的kind值:

PTHREAD_MUTEX_NORNAL //不做任何特殊的错误检查或死锁检测,没有解锁后重新加锁会死锁。PTHREAD_MUTEX_RECURSIVE //嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争;PTHREAD_MUTEX_ERRORCHECK //检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,即没有解锁后重新加锁会返回错误;PTHREAD_MUTEX_ADAPTIVE //适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

5.递归锁与非递归锁(嵌套锁与非嵌套锁)

mutex可以分为递归锁(recursive mutex)和非递归锁(non-recursive mutex)。可递归锁也可称为可重入锁(reentrant mutex),非递归锁又叫不可重入锁(non-reentrant mutex)。

二者唯一的区别是,同一个线程可以多次获取同一个递归锁,不会产生死锁。而如果一个线程多次获取同一个非递归锁,则会产生死锁。

Windows下的Mutex和Critical Section是可递归的。Linux下的pthread_mutex_t锁默认是非递归的。可以显示的设置PTHREAD_MUTEX_RECURSIVE属性,将pthread_mutex_t设为递归锁。

MutexLock mutex; void foo() { mutex.lock(); // do something mutex.unlock(); } void bar() { mutex.lock(); // do something foo(); mutex.unlock(); }

foo函数和bar函数都获取了同一个锁,而bar函数又会调用foo函数。如果MutexLock锁是个非递归锁,则这个程序会立即死锁。因此在为一段程序加锁时要格外小心,否则很容易因为这种调用关系而造成死锁。

6.例子 example_1.cpp

8 9 #include 10 #include 11 12 13 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 14 15 int count = 0; 16 void* threadFunc(void*) 17 { 18 for(int i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3